import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*; 

public class CFB extends Mode
{
	//size of block to be encrypted in bytes
	public int k = 1;
	
	public CFB() {}
	
	public byte[] Encrypt(SecretKey key1, SecretKey key2, byte[] IV, byte[] plainText) throws Exception
	{
		if (IV.length != 8) 
			throw new Exception("CFB Encryption: Initalization Vector size =! 8");
	
		int textLength = plainText.length;
		int r = textLength % 8;
		
		int cipherLength;
		if (r == 0)
			cipherLength = textLength;
		else
			cipherLength = textLength + (8 - r);
		
		if (r != 0)
			plainText = Arrays.copyOf(plainText, cipherLength);
		
		byte[] cipherText = new byte[cipherLength];
		byte[] currentBlock = new byte[k];
		byte[] IVTransformation = Arrays.copyOf(IV, 8);
		
		TripleDES des = new TripleDES();
		
		for (int i = 0; i < cipherLength; i += k)
		{
			if (i > 0)
			{
				//shift
				byte[] temp = new byte[8];
				ReplaceBlock(temp, Arrays.copyOfRange(IVTransformation, k, 8), 0);
				ReplaceBlock(temp, currentBlock, 8 - k);
				IVTransformation = temp;
			}

			currentBlock = Arrays.copyOfRange(des.Encrypt(key1, key2, IVTransformation), 0, k);
			currentBlock = XOR(Arrays.copyOfRange(plainText, i, i + k), currentBlock);		
			ReplaceBlock(cipherText, currentBlock, i);
		}
		
		return cipherText;
	}
	
	public byte[] Decrypt(SecretKey key1, SecretKey key2, byte[] IV, byte[] cipherText) throws Exception
	{
		if (IV.length != 8) 
			throw new Exception("CFB Decryption: Initalization Vector size =! 8");
		
		int cipherLength = cipherText.length;
		int r = cipherLength % 8;
		
		if (r != 0)
			throw new Exception("CFB Decryption: cipherText size is not a multiple of 8");
		
		byte[] plainText = new byte[cipherLength];
		byte[] currentBlock = new byte[k];
		byte[] IVTransformation = Arrays.copyOf(IV, 8);
		
		TripleDES des = new TripleDES();
		
		for (int i = 0; i < cipherLength; i += k)
		{
			if (i > 0)
			{
				//shift
				byte[] temp = new byte[8];
				ReplaceBlock(temp, Arrays.copyOfRange(IVTransformation, k, 8), 0);
				ReplaceBlock(temp, currentBlock, 8 - k);
				IVTransformation = temp;
			}

			currentBlock = Arrays.copyOfRange(des.Encrypt(key1, key2, IVTransformation), 0, k);
			currentBlock = XOR(Arrays.copyOfRange(cipherText, i, i + k), currentBlock);		
			ReplaceBlock(plainText, currentBlock, i);
			currentBlock = Arrays.copyOfRange(cipherText, i, i + k);
		}
		
		return plainText;
	}
}













